# !/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import os
import json
import psycopg2
import traceback
from xtls.timeparser import now

from company_crawler_util import camel_to_underline
from company_crawler_util import InsertError
from company_crawler_util import get_db_config
from cleaner import Cleaner

ROOT_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))
if ROOT_PATH not in sys.path:
    sys.path.append(ROOT_PATH)


reload(sys)
sys.setdefaultencoding('utf-8')

class XsbBaseHandler(object):
    def __init__(self, stock, data, tab_op, logger):
        self.stock = stock
        self.data = data
        self.tab_op = tab_op
        self.logger = logger
        self.unfinished_id = set()
        db_config = get_db_config(ROOT_PATH)
        self.conn = psycopg2.connect(database=db_config['db'], host=db_config['host'], port=db_config['port'],
                                     user=db_config['user'], password=db_config['pw'])
        self.cur = self.conn.cursor()
        self.cleaner = Cleaner()
        self.tab_name = ''
        self.total = 0

    def parse(self):
        raise NotImplementedError()

    def save(self, data):
        if not data:
            self._modify_tab_op_to_nothing(self.stock.id)
            return

        method_mapping = {
            'NEW': self.save_update,
            'UPDATE': self.save_update,
            'INSERT': self.save_insert,
            'PRINT': self.save_print,
            'NOTHING': self.save_nothing,
        }
        method = method_mapping.get(self.tab_op, None)
        if method:
            method(data)
            self._modify_tab_op_to_nothing(self.stock.id)
        else:
            self.logger.warn('SAVE METHOD ERROR: stockID: %s, tab_op: %s' % (self.stock.stock_code, self.tab_op))

    def save_update(self, data):
        pass

    def save_insert(self, data):
        pass

    def save_print(self, data):
        pass

    def save_nothing(self, data):
        pass

    def _modify_tab_op_to_nothing(self, stock_id):
        tab_op_name = '%s_op' % self.tab_name
        sql = 'UPDATE stock set %s=%s WHERE id=%s'
        sql = sql % (tab_op_name, '%s', '%s')
        try:
            self.cur.execute(sql, ('NOTHING', stock_id))
            self.conn.commit()
        except Exception, e:
            self.logger.exception('Non Modify %s to nothing. Error: %s' % (tab_op_name, e.__str__()))
            raise InsertError(e)

    def _run(self):
        data = self.parse()
        try:
            self.save(data)
            self.logger.info('Save: %s-%s-%s' % (self.stock.stock_code, self.tab_name, self.tab_op))
        except InsertError, e:
            self.logger.exception('Non SAVE: %s-%s-%s' % (self.stock.stock_code, self.tab_name, self.tab_op))
            self.conn.commit()
            self.unfinished_id.add(self.stock.id)

    def run(self):
        if self.tab_op == 'NOTHING':
            self.logger.info('%s-%s-NOTHING' % (self.stock.stock_code, self.tab_name))
        else:
            self._run()

        self.cur.close()
        self.conn.close()

    def get_unfinished_id(self):
        return self.unfinished_id

# --------------------------util---------------------------------
    def insert_to_db(self, table_name, cleaned_data):
        cleaned_data['updateTime'] = now()
        key_list = [camel_to_underline(key) for key in cleaned_data.keys()]
        table_name = 'company_%s' % table_name
        sql = 'INSERT INTO %s (%s) VALUES (%s)'
        sql = sql % (table_name, ','.join(key_list), ','.join(['%s' for _ in xrange(len(key_list))]))
        try:
            self.cur.execute(sql, cleaned_data.values())
            self.conn.commit()
        except Exception:
            trace = traceback.format_exc()
            raise InsertError(trace)

    def select_current_version_num(self, table_name, stock_id):
        table_name = 'company_%s' % table_name
        sql = 'SELECT MAX(version_num) FROM %s WHERE stock_id = %s'
        sql = sql % (table_name, '%s')
        self.cur.execute(sql, (stock_id,))
        version_num = self.cur.fetchone()[0]
        return version_num if version_num else 0
